﻿/*======================================*\
* Author: Vincent
* LastModifyUser: Vincent
* Description:  
* CreateTime： 2012-05
* Remark:  
\*======================================*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using AppCode.DbDTO;
using AppCode.Contract;
using AppCode.Util;


namespace AppCode.Domain.Services
{
    [Serializable]
    /// <summary>
    /// 生成代码
    /// <para>
    ///  此类为临时处理方法，对模板的应用很肤浅，后面需要重构，现在赶时间先这样
    /// </para>
    /// </summary>
    public class CodeCreateHandler : ICodeCreate
    {
        #region 私有变量
        /// <summary>
        /// 默认的代码模板路径
        /// </summary>
        private  string _templateCodePath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Template\\defaultTemplate.tt";

        /// <summary>
        /// 生成代码保存路径(默认)
        /// </summary>
        private string _codeFilePath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "CodeFile\\Entity\\";

        /// <summary>
        /// 命名空间
        /// </summary>
        private string _nameSpaceName = "";

        private IList<TableInfo> _tableInfos;

        #region 代码文件容器
        private StringBuilder _sbMain = new StringBuilder();
        private StringBuilder _sbPrivate = new StringBuilder();
        private StringBuilder _sbPublic = new StringBuilder();
        #endregion

        /// <summary>
        /// 执行生成的异步线程
        /// </summary>
        private BackgroundWorker _bgWorkCodeCreate = null;

        #endregion

        #region 模板常量

        /// <summary>
        /// 代码模板替换-类名(表名)
        /// </summary>
        protected const string CODECREATE_CLASSNAME = "$TableName$";

        /// <summary>
        /// 创建时间
        /// </summary>
        protected const string CODECREATE_CREATETIME = "$CreateTime$";

        /// <summary>
        /// 主键
        /// </summary>
        protected const string CODECREATE_PRIMARYKEY = "$PrimaryKey$";

        /// <summary>
        /// 命名空间
        /// </summary>
        protected const string CODECREATE_NAMESPACENAME = "$ProjectNameSpace$";

        /// <summary>
        /// 私有属性替换 
        /// </summary>
        protected const string CODECREATE_PRIVATEPROPERTY = "$PrivatePropertys$";

        /// <summary>
        /// 公有属性替换
        /// </summary>
        protected const string CODECREATE_PUBLICEPROPERTY = "$PublicPropertys$";

        /// <summary>
        /// 数据类型替换
        /// </summary>
        protected const string CODECREATE_DATATYPE = "$DataType$";

        /// <summary>
        /// 私有字段名
        /// </summary>
        protected const string CODECREATE_COLUMNNAME_PRIVATE = "$ColumnNamePrivate$";

        /// <summary>
        /// 公有字段名
        /// </summary>
        protected const string CODECREATE_COLUMNNAME_PUBLIC = "$ColumnName$";


        #endregion

        #region 私有方法 
        /// <summary>
        /// 加载模板文件
        /// </summary>
        private void LoadTempLateFile()
        {
            using (StreamReader sdr = new StreamReader(_templateCodePath))
            {
                string strTmp = "";
                while (strTmp != null)
                {
                    strTmp = sdr.ReadLine();
                    if (!string.IsNullOrEmpty(strTmp))
                        _sbMain.AppendLine(strTmp);
                }
                sdr.Close();
            }
        }

        /// <summary>
        /// 生成私有属性
        /// </summary>
        /// <param name="tableinfo"></param>
        private string CreatePrivatePropertys(List<TableInfo> tableinfo,ref StringBuilder sbTmp)
        {
            StringBuilder sb = new StringBuilder();

            #region 生成私有属性
            //查找主键
            
            var isHavePrimaryKey = tableinfo.Find(a => a.IsPrimaryKey == "1" || a.IsIdentity=="1");
            if (isHavePrimaryKey != null)
                sbTmp.Replace(CODECREATE_PRIMARYKEY, isHavePrimaryKey.ColumnName);
            else
            {
                //若无主键及自增列，则取一个int类型的，int类型的都没有，那就是木有了
                var _item = tableinfo.Find(a => a.ColumnType == "int");
                if (_item != null)
                    sbTmp.Replace(CODECREATE_PRIMARYKEY, _item.ColumnName);
                else
                    sbTmp.Replace(CODECREATE_PRIMARYKEY, "[找不到主键]");
            }
            
            foreach (var item in tableinfo)
            {
                if (item.IsPrimaryKey == "1")
                    sbTmp.Replace(CODECREATE_PRIMARYKEY, item.ColumnName);
                sb.AppendFormat("\t\t private {1} _{0};\r\n",item.ColumnName.ToLower(),item.ColumnType);
            }
            
            
            #endregion 

            return sb.ToString();

        }

        /// <summary>
        /// 生成公共属性
        /// </summary>
        /// <param name="tableinfo"></param>
        /// <param name="sbTmp"></param>
        /// <returns></returns>
        private string CreatePublicProperty(List<TableInfo> tableinfo, ref StringBuilder sbTmp)
        {
            StringBuilder sb = new StringBuilder();
            CodeCreatePropertyHandler hander = new CodeCreatePropertyHandler();
            string[] specialType = {"int","bool","float","double","decimal","short","long" };  //特殊类型处理
            #region 生成公有属性
            List<TableInfo> isUse = new List<TableInfo>();
            foreach (var item in tableinfo)
            {
                if (item.IsPrimaryKey=="1" && !isUse.Contains(item))  //是主键
                {
                    sb.Append(hander.ColumnPrimaryKeyStr(item));
                    isUse.Add(item);
                }
                else if (item.IsIdentity == "1"  && !isUse.Contains(item))//标识列
                {
                    sb.Append(hander.ColumnTagStr(item));
                    isUse.Add(item);
                }
                else if (specialType.Contains(item.ColumnType)  && !isUse.Contains(item))
                {
                    sb.Append(hander.ColumnSpecialTypeStr(item));
                    isUse.Add(item);
                }
                else
                {
                    sb.Append(hander.ColumnPublicStr(item));
                    isUse.Add(item);
                }
            }
            #endregion

            return sb.ToString();
        }

        /// <summary>
        /// 创建代码文件
        /// </summary>
        /// <param name="tables"></param>
        private void CreateCodeFile(IList<string> tables)
        {
            StringBuilder sbTmp = new StringBuilder();
           
            foreach (var item in tables)
            {
                sbTmp.Append(_sbMain.ToString()); //得到模板文件的一个副本
                ReportLogToTextEvent(this, new TaskInfoEventArgs() { dt = DateTime.Now, msg = string.Format("[{0}] 生成表[{1}]的DTO\r\n", DateTime.Now.ToString(), item) });
                #region 替换模板文件
                sbTmp.Replace(CODECREATE_CLASSNAME, item.ToString());
                sbTmp.Replace(CODECREATE_CREATETIME, DateTime.Now.ToString());
                sbTmp.Replace(CODECREATE_NAMESPACENAME, _nameSpaceName);

                List<TableInfo> tmpInfo = _tableInfos.Where(a => a.TableName == item).ToList(); //表信息集合

                #region 生成私有属性
                string tmpProperty = CreatePrivatePropertys(tmpInfo,ref sbTmp);  //生成私有属性
                sbTmp.Replace(CODECREATE_PRIVATEPROPERTY, tmpProperty);
                #endregion

                #region 生成公共属性
                string tmpPublicProperty = CreatePublicProperty(tmpInfo, ref sbTmp);
                sbTmp.Replace(CODECREATE_PUBLICEPROPERTY, tmpPublicProperty);
                #endregion

                #endregion
                CreateFileToDisk(sbTmp, string.Format("{0}.cs", item));
                sbTmp.Length = 0;
            }
        }

        private static object lockObj = new object();
        /// <summary>
        /// 生成代码文件
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="fileName"></param>
        private void CreateFileToDisk(StringBuilder sb , string fileName)
        {
            lock (lockObj)
            {
                string path = _codeFilePath + fileName;
                using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8))
                {
                    sw.Write(sb.ToString());
                    sw.Close();
                }
                System.Threading.Thread.Sleep(50);
            }
        }
        #endregion

        /// <summary>
        /// 报告生成情况的事件
        /// </summary>
        public event EventHandler<TaskInfoEventArgs> ReportLogToTextEvent;

        #region 构造

        public CodeCreateHandler() { }

        /// <summary>
        /// 初始化工作线程
        /// </summary>
        /// <param name="path"></param>
        /// <param name="nameSpaceName"></param>
        public CodeCreateHandler(string path,string nameSpaceName)
        {
            this._codeFilePath = path;
            this._nameSpaceName = nameSpaceName;

            _bgWorkCodeCreate = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
            _bgWorkCodeCreate.DoWork += new DoWorkEventHandler(_bgWorkCodeCreate_DoWork);
            _bgWorkCodeCreate.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_bgWorkCodeCreate_RunWorkerCompleted);
        }
        #endregion

        /// <summary>
        /// 执行完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _bgWorkCodeCreate_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ReportLogToTextEvent(this, new TaskInfoEventArgs() { msg = "============>已全部生成!",statecode = 100 });
        }

        /// <summary>
        /// 执行任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _bgWorkCodeCreate_DoWork(object sender, DoWorkEventArgs e)
        {
            CreateCodeFile((IList<string>)e.Argument);
        }


        /// <summary>
        /// 创建代码
        /// <para>
        /// 并初始化数据信息
        /// </para>
        /// </summary>
        /// <param name="nameSpace"></param>
        public void Create()
        {
            if (DbInfoInit.DbInfos != null)
            {
                IList<string> tables = DbInfoInit.DbInfos.DbTablesNeedHandler;//只处理需要处理的
                _tableInfos = DbInfoInit.DbInfos.DbTableInfo;
                foreach (var item in _tableInfos)
                {
                    item.ColumnType = SqlTypeToCshare.ChangeToCSharpType(item.ColumnType, item.IsAlowNull);
                    item.ColumnRemark = item.ColumnRemark.Replace("\r\n", "");
                }
                if (tables == null || _tableInfos == null)
                    throw new Exception("读取静态数据库相关信息失败!对象未初始化!");
                LoadTempLateFile();
                _bgWorkCodeCreate.RunWorkerAsync(tables);
            }
        }

        
    }
}
